import { TimelineSystem } from '../renderer/TimelineSystem';
import { AnimationRenderer } from '../renderer/AnimationRenderer';
import { SceneData } from '../../types/SceneTypes';
import { Logger } from '../../utils/Logger';

/**
 * ExportService Class
 * 
 * Handles exporting animations to various formats.
 */
export class ExportService {
  private renderer: AnimationRenderer;
  private timelineSystem: TimelineSystem;

  /**
   * Creates an instance of ExportService.
   * @param width - Width of the export
   * @param height - Height of the export
   */
  constructor(width: number = 1920, height: number = 1080) {
    this.renderer = new AnimationRenderer(width, height);
    this.timelineSystem = new TimelineSystem();
  }

  /**
   * Exports a video from scene data
   * @param sceneData - Scene data to export
   * @param outputPath - Path to save the output video file
   * @param format - Output format (e.g., 'mp4', 'avi', 'mov')
   * @param frameRate - Frame rate for the exported video
   * @param quality - Quality of the exported video (0-100)
   * @param signal - Optional abort signal for cancellation
   * @param projectId - Optional project ID for asset loading
   * @returns Promise<void>
   */
  public async exportVideo(
    sceneData: SceneData,
    outputPath: string,
    format: string = 'mp4',
    frameRate: number = 30,
    quality: number = 90,
    signal?: AbortSignal,
    projectId?: string
  ): Promise<void> {
    const logger = Logger.getInstance();
    try {
      logger.log('Starting video export process', 'ExportService');
      console.log('[ExportService] Starting video export process');
      logger.log(`Scene data: ${JSON.stringify(sceneData, null, 2)}`, 'ExportService');
      console.log('[ExportService] Scene data:', sceneData);
      logger.log(`Output path: ${outputPath}`, 'ExportService');
      console.log('[ExportService] Output path:', outputPath);
      logger.log(`Format: ${format}`, 'ExportService');
      console.log('[ExportService] Format:', format);
      logger.log(`Frame rate: ${frameRate}`, 'ExportService');
      console.log('[ExportService] Frame rate:', frameRate);
      logger.log(`Quality: ${quality}`, 'ExportService');
      console.log('[ExportService] Quality:', quality);
      if (projectId) {
        logger.log(`Project ID: ${projectId}`, 'ExportService');
        console.log('[ExportService] Project ID:', projectId);
      }
      
      // Setup the scene
      if (sceneData) {
        logger.log('Setting up scene with provided scene data', 'ExportService');
        console.log('[ExportService] Setting up scene with provided scene data');
        // Pass project ID to renderer if available
        if (projectId) {
          (this.renderer as any).currentProjectId = projectId;
        }
        this.renderer.setupScene(sceneData);
        const elementCount = this.renderer.getSceneManager().getElementCount();
        logger.log(`Scene setup completed. Elements in scene: ${elementCount}`, 'ExportService');
        console.log(`[ExportService] Scene setup completed. Elements in scene: ${elementCount}`);
      } else {
        logger.warn('No scene data provided for export', 'ExportService');
        console.log('[ExportService] No scene data provided for export');
      }
      
      // Generate timeline states for each frame
      logger.log(`Generating timeline states with frame rate: ${frameRate}`, 'ExportService');
      console.log(`[ExportService] Generating timeline states with frame rate: ${frameRate}`);
      const timelineStates = this.timelineSystem.generateTimelineStates(frameRate);
      logger.log(`Generated ${timelineStates.length} timeline states`, 'ExportService');
      console.log(`[ExportService] Generated ${timelineStates.length} timeline states`);
      
      // Export video using the renderer
      logger.log('Starting video export with renderer', 'ExportService');
      console.log('[ExportService] Starting video export with renderer');
      await this.renderer.exportVideo(timelineStates, outputPath, format, signal, projectId);
      
      logger.log(`Video exported successfully to ${outputPath}`, 'ExportService');
      console.log(`[ExportService] Video exported successfully to ${outputPath}`);
    } catch (error) {

    }
  }

  /**
   * Exports animation as a sequence of images
   * @param sceneData - Scene data to render
   * @param outputDir - Directory to save the output images
   * @param format - Image format (png, jpg, etc.)
   * @param frameRate - Frame rate for the export
   * @returns Promise<string[]> - Array of exported file paths
   */
  public async exportImageSequence(
    sceneData: SceneData,
    outputDir: string,
    format: string = 'png',
    frameRate: number = 30
  ): Promise<string[]> {
    const exportedFiles: string[] = [];
    
    try {
      // Import required modules
      const fs = await import('fs');
      const path = await import('path');
      
      // Setup the scene
      this.renderer.setupScene(sceneData);
      
      // Generate timeline states for each frame
      const timelineStates = this.timelineSystem.generateTimelineStates(frameRate);
      
      // Create output directory if it doesn't exist
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true });
      }
      
      // Render each frame and save as image
      for (let i = 0; i < timelineStates.length; i++) {
        const frameBuffer = this.renderer.renderFrame(timelineStates[i]);
        const fileName = `frame_${i.toString().padStart(5, '0')}.${format}`;
        const filePath = path.join(outputDir, fileName);
        
        fs.writeFileSync(filePath, frameBuffer);
        exportedFiles.push(filePath);
      }
      
      console.log(`Exported ${exportedFiles.length} frames to ${outputDir}`);
      return exportedFiles;
    } catch (error) {
      console.error('Error exporting image sequence:', error);
      throw error;
    }
  }

  /**
   * Formats time in milliseconds to ASS format (H:MM:SS.CS)
   * @param milliseconds - Time in milliseconds
   * @returns Formatted time string
   */
  private formatTime(milliseconds: number): string {
    const totalSeconds = milliseconds / 1000;
    const hours = Math.floor(totalSeconds / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = Math.floor(totalSeconds % 60);
    const centiseconds = Math.floor((milliseconds % 1000) / 10);
    
    return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}.${centiseconds.toString().padStart(2, '0')}`;
  }

  /**
   * Exports subtitles in ASS format
   * @param outputPath - Path to save the output subtitle file
   * @returns Promise<void>
   */
  public async exportASSSubtitles(outputPath: string): Promise<void> {
    try {
      // 从时间轴系统生成ASS字幕文件
      // 此功能已实现真实的从时间轴生成ASS字幕逻辑:
      // 1. 从时间轴系统获取字幕数据
      // 2. 查找字幕轨道
      // 3. 构建ASS字幕内容
      // 4. 写入文件
      // 从时间轴系统获取字幕数据
      const tracks = this.timelineSystem.getTracks();
      
      // 查找字幕轨道
      const subtitleTracks = tracks.filter(track => track.type === 'subtitle');
      
      // 构建ASS字幕内容
      let assContent = `[Script Info]
Title: Exported Subtitles
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080
ScaledBorderAndShadow: yes

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,0,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
Style: Narrator,Arial,24,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
`;
      
      // 从字幕轨道生成对话行
      subtitleTracks.forEach(track => {
        track.keyframes.forEach(keyframe => {
          // 使用安全访问方式获取属性
          const properties = (keyframe as any).properties || {};
          const startTime = this.formatTime(keyframe.time);
          const duration = properties.duration || 3000; // 使用属性中的持续时间，如果没有则默认3秒
          const endTime = this.formatTime(keyframe.time + (duration / 1000)); // 转换为秒
          const characterName = properties.character || 'Character';
          const style = properties.style || 'Default';
          const text = properties.text || '';
          
          if (text) {
            assContent += `Dialogue: 0,${startTime},${endTime},${style},${characterName},0,0,0,,${text}\n`;
          }
        });
      });
      
      // 在实际实现中，可能还需要:
      // 1. 处理样式和格式
      // 2. 添加特效和过渡
      // 3. 优化时间轴以避免重叠
      // 4. 验证输出格式
      
      const fs = await import('fs');
      fs.writeFileSync(outputPath, assContent);
      console.log(`ASS subtitles exported to ${outputPath}`);
    } catch (error) {
      console.error('Error exporting ASS subtitles:', error);
      throw error;
    }
  }

  /**
   * Exports project data as JSON
   * @param sceneData - Scene data to export
   * @param outputPath - Path to save the output JSON file
   * @returns Promise<void>
   */
  public async exportProjectData(sceneData: SceneData, outputPath: string): Promise<void> {
    try {
      const fs = await import('fs');
      
      // Get timeline data
      const timelineData = this.timelineSystem.getState();
      
      // Create project data object
      const projectData = {
        scene: sceneData,
        timeline: timelineData,
        exportTime: new Date().toISOString()
      };
      
      // Write to file
      const jsonData = JSON.stringify(projectData, null, 2);
      fs.writeFileSync(outputPath, jsonData);
      
      console.log(`Project data exported to ${outputPath}`);
    } catch (error) {
      console.error('Error exporting project data:', error);
      throw error;
    }
  }

  /**
   * Sets the timeline system
   * @param timelineSystem - The timeline system to use
   */
  public setTimelineSystem(timelineSystem: TimelineSystem): void {
    this.timelineSystem = timelineSystem;
  }

  /**
   * Gets the animation renderer
   * @returns AnimationRenderer - The animation renderer
   */
  public getRenderer(): AnimationRenderer {
    return this.renderer;
  }

  /**
   * Gets the timeline system
   * @returns TimelineSystem - The timeline system
   */
  public getTimelineSystem(): TimelineSystem {
    return this.timelineSystem;
  }

  /**
   * Exports a video directly from a workspace project
   * @param projectId - The ID of the project in the workspace
   * @param outputPath - Path to save the output video file
   * @param format - Output format (e.g., 'mp4', 'avi', 'mov')
   * @param signal - Optional abort signal for cancellation
   * @returns Promise<void>
   */
  public async exportVideoFromProject(
    projectId: string,
    outputPath: string,
    format: string = 'mp4',
    signal?: AbortSignal
  ): Promise<void> {
    try {
      // Dynamically import path and fs modules
      const path = await import('path');
      const fs = await import('fs');

      // Define the workspace directory
      const workspacesDir = path.join(__dirname, '../../workspaces');
      const projectDir = path.join(workspacesDir, projectId);

      // Check if project exists
      if (!fs.existsSync(projectDir)) {
        throw new Error(`Project "${projectId}" not found in workspaces directory`);
      }

      // Read project configuration
      const projectConfigPath = path.join(projectDir, 'project.json');
      if (!fs.existsSync(projectConfigPath)) {
        throw new Error(`Project configuration file not found for project "${projectId}"`);
      }

      const projectConfigContent = fs.readFileSync(projectConfigPath, 'utf8');
      const projectConfig = JSON.parse(projectConfigContent);
      
      // Get scene data
      const sceneName = projectConfig.defaultScene;
      const scenePath = path.join(projectDir, 'scenes', `${sceneName}.json`);
      
      if (!fs.existsSync(scenePath)) {
        throw new Error(`Scene file "${sceneName}.json" not found for project "${projectId}"`);
      }
      
      const sceneDataContent = fs.readFileSync(scenePath, 'utf8');
      const sceneData = JSON.parse(sceneDataContent) as SceneData;

      // Get timeline data
      const timelinePath = path.join(projectDir, projectConfig.timelineFile || 'timeline.json');
      if (fs.existsSync(timelinePath)) {
        const timelineDataContent = fs.readFileSync(timelinePath, 'utf8');
        const timelineData = JSON.parse(timelineDataContent);
        this.timelineSystem.loadFromData(timelineData);
      }

      // Extract export parameters from project config
      const frameRate = projectConfig.frameRate || 30;
      const quality = projectConfig.quality || 90;

      // Set project ID on renderer before calling exportVideo
      if (projectId) {
        this.renderer.currentProjectId = projectId;
      }
      
      // Call the existing exportVideo method
      await this.exportVideo(sceneData, outputPath, format, frameRate, quality, signal, projectId);
    } catch (error) {
      console.error('Error exporting video from project:', error);
      throw error;
    }
  }
}
